package com.atguigu.gmall.wms.listener;

import com.atguigu.gmall.wms.entity.WareSkuEntity;
import com.atguigu.gmall.wms.mapper.WareSkuMapper;
import com.atguigu.gmall.wms.service.WareSkuService;
import com.atguigu.gmall.wms.vo.SkuLockVo;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.List;

@Component
@Slf4j
public class StockMqListener {
    String skuLockVosKeyPrefix = "sku:locks:";
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    WareSkuService wareSkuService;
    @Autowired
    WareSkuMapper wareSkuMapper;
    Gson gson = new Gson();
    //监听支付成功消息：更新订单支付状态
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue("order-success-queue"),
            exchange = @Exchange(value = "order_exchange" , type = ExchangeTypes.TOPIC,
                    ignoreDeclarationExceptions = "true"),
            key = "order.submit.success"
    ))
    public void ordersubmitSuccessListener(Message message , Channel channel , String orderToken) throws IOException {
        try {
            String skuLockVosJson = redisTemplate.opsForValue().get(skuLockVosKeyPrefix + orderToken);
            log.info("wms服务，订单创建失败，释放库存 : {}, 要释放的库存信息：{}",orderToken ,skuLockVosJson);
            if(StringUtils.isNotBlank(skuLockVosJson)){
                List<SkuLockVo> skuLockVos = gson.fromJson(skuLockVosJson, new TypeToken<List<SkuLockVo>>() {}.getType());
                skuLockVos.forEach(skuLockVo -> {
                    //减库存： 库存的数量-count, 锁定库存的数量-count,销量+count
                    WareSkuEntity wareSkuEntity = wareSkuService.getById(skuLockVo.getWareSkuId());
                    wareSkuEntity.setSales(wareSkuEntity.getSales()+skuLockVo.getCount());
                    wareSkuEntity.setStock(wareSkuEntity.getStock() - skuLockVo.getCount());
                    wareSkuEntity.setStockLocked(wareSkuEntity.getStockLocked() - skuLockVo.getCount());
                    wareSkuService.updateById(wareSkuEntity);
                });
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (Exception e) {
            e.printStackTrace();
            if(message.getMessageProperties().isRedelivered()){
                channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
            }else{
                channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
            }
        }
    }
    //释放库存消息的监听器
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue("stock-unlock-queue"),
                    exchange = @Exchange(value = "order_exchange" , type = ExchangeTypes.TOPIC ,
                                    ignoreDeclarationExceptions = "true" ),
                    key = {"stock.unlock"}
            )
    })
    public void unlockStockListener(Message message , Channel channel , String orderToken) throws IOException {

        try {
            //执行释放库存的业务
            String skuLockVosJson = redisTemplate.opsForValue().get(skuLockVosKeyPrefix + orderToken);
            log.info("wms服务，订单创建失败，释放库存 : {}, 要释放的库存信息：{}",orderToken ,skuLockVosJson);
            if(StringUtils.isNotBlank(skuLockVosJson)){
                //Gson:如果需要将json转为复杂类型的对象  需要借助于TypeToken实现
                List<SkuLockVo> skuLockVos = gson.fromJson(skuLockVosJson, new TypeToken<List<SkuLockVo>>() {}.getType());
                skuLockVos.forEach(skuLockVo -> {
                   //释放库存
                    wareSkuMapper.unlockStock(skuLockVo.getWareSkuId() , skuLockVo.getCount());
                });
                //删除已经释放库存的 redis中缓存的库存锁定信息
                redisTemplate.delete(skuLockVosKeyPrefix + orderToken);
            }
            //手动ack
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (Exception e) {
            e.printStackTrace();
            //执行时有异常
            //重试一次
            if(message.getMessageProperties().isRedelivered()){//消息消费失败第二次
                //丢弃消息： 丢弃到死信队列
                channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
            }else{//消息第一次消费失败，重试
                channel.basicNack(message.getMessageProperties().getDeliveryTag(),false , true);
            }
        }

    }

}
